﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace net第五次作业
{
    public partial class Form1 : Form
    {
        private const int MaxPhoneNumbers = 100; // 要获取的最大电话号码数量
        private HttpClient httpClient = new HttpClient();
        private HashSet<string> phoneNumbers = new HashSet<string>(); // 存储不重复的电话号码
        string nextPageUrl = string.Empty;

        public Form1()
        {
            InitializeComponent();
        }
        // 按钮点击事件：开始爬取
        private async void buttonSearch_Click(object sender, EventArgs e)
        {
            string keyword = textBoxKeyword.Text.Trim();
            if (string.IsNullOrEmpty(keyword))
            {
                MessageBox.Show("请输入关键词！");
                return;
            }

            progressBar.Value = 0;
            listBoxResults.Items.Clear();
            phoneNumbers.Clear();
            string searchUrls = GenerateSearchUrls(keyword); // 生成搜索引擎URL
            nextPageUrl = searchUrls; // 下一页
            await CrawlAsync(searchUrls); // 异步爬取
            int first = 10;
            while (phoneNumbers.Count < 100)
            {
                await CrawlAsync(nextPageUrl+"&first="+first);
                first += 10;
            }

            MessageBox.Show($"爬取完成，共找到 {phoneNumbers.Count} 个电话号码！");
        }

        //本来想实现两个一起搜索的
        // 生成 Baidu 和 Bing 的搜索 URL
        private string GenerateSearchUrls(string keyword)
        {
            
            //$"https://www.baidu.com/s?wd={Uri.EscapeDataString(keyword)}",
           return $"https://www.bing.com/search?q={Uri.EscapeDataString(keyword)}";
        }


        

        // 异步爬取网页
        private async Task CrawlAsync(string urls)
        {
            List<Task> tasks = new List<Task>(); // 多任务并发
            tasks.Add(Task.Run(() => CrawlPageAsync(urls)));
            await Task.WhenAll(tasks); // 等待所有任务完成
        }

        // 爬取单个页面并提取电话号码
        private async Task CrawlPageAsync(string url)
        {   

            if (phoneNumbers.Count >= MaxPhoneNumbers) { return; }
            try
            {   
                Console.WriteLine(url);
                 //发出请求
                string html = await httpClient.GetStringAsync(url);
                
                //提取不重复的number
                HashSet<string> foundNumbers = ExtractPhoneNumbers(html);

                //防止进程访问冲突
                lock (phoneNumbers)
                {   
                    //这里可以发现每次找到的电话是十几条
                    //后面调试发现其中很多都是重复的
                    //基本上每页只有几条是不重复的
                    Console.WriteLine(foundNumbers.Count);
                    foreach (string number in foundNumbers)
                    {
                        if (phoneNumbers.Count >= MaxPhoneNumbers) break;

                        if (!phoneNumbers.Contains(number))
                        {
                            phoneNumbers.Add(number);
                            Invoke(new Action(() => listBoxResults.Items.Add($"{number} - {url}")));
                        }
                    }
                }

                Invoke(new Action(() => progressBar.Value = Math.Min(progressBar.Value + 1, 100)));
                /*
                    List<string> urls = ExtractNextPageUrls(html);
                    if (urls.Count > 0)
                    {
                    //这里本来想直接找到下一个网址然后直接访问的，但是发现它这里会存在很多的字符转码问题，导致地址无法正确转换
                    //尝试了一些步骤没有完全解决 效果不是很好 （用来webutility，可能是用得不对；还有找不到httputility）
                    //发现了可以直接修改参数first实现不同页的访问,这个用起来很简单

                    //nextPageUrl = "https://www.bing.com" + System.Net.WebUtility.UrlDecode(urls[0]);
                    Console.WriteLine($"发现下一页: {nextPageUrl}");
                    }
                */
            }
            catch (Exception ex)
            {
                Invoke(new Action(() => listBoxResults.Items.Add($"Error: {ex.Message}")));
            }
        }
        //寻找下一页的网址
        private List<string> ExtractNextPageUrls(string html)
        {
            // 匹配带有特定文本的<a>标签，并提取href属性
            Regex nextPageRegex = new Regex(@"<a[^>]*aria-label=""下一页""[^>]*href=""([^""]*)""[^>]*>.*?</a>", RegexOptions.Singleline);
            MatchCollection matches = nextPageRegex.Matches(html);
            return matches.Cast<Match>().Select(m => m.Groups[1].Value).ToList();
    }
        // 正则表达式提取电话号码
        private HashSet<string> ExtractPhoneNumbers(string html)
        {
            Regex phoneRegex = new Regex(@"\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}");
            MatchCollection matches = phoneRegex.Matches(html);
            return matches.Cast<Match>().Select(m => m.Value).ToHashSet();
        }
    }
}